package com.oracle.calllog.producer;

import com.oracle.common.PropertiesUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;

import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 通话日志数据仿真系统的完全实现类,是在标准版仿真引擎的基础上增加随机的异常数据(垃圾数据)信息<BR>
 * 本仿真系统模拟格式标准如下:<BR>
 * <B>通话编号 主叫人所在城市 主叫人网络类型(2G|3G|4G|5G) 主叫人移动卡业务类型(全球通|神州行|动感地带) 主叫号码 主叫人姓名 被叫人所在城市 被叫人网络类型(2G|3G|4G|5G) 被叫人运营商类型(移动|联通|电信)被叫号码 被叫人姓名 通话开始时间 通话时长 通话类型(接通|未接通|语音信箱)</B><BR>
 * 本系统标准格式的示例如下所示:<BR>
 * <I>abcd1234efgh5678ijkl9012mnop3456 110000 5G M-Zone 18888888888 张飞 110000 4G CMCC 16666666666 关羽 2020-01-09_08:09:10 0090 CONNECT_CALL</I><BR>
 *
 * @author Mr.Chen
 * @version 2.0.6
 * @time 2021-1-8
 */
public class CallLogsFullSimulationProducer extends CallLogsStandardSimulationProducer {

    /**
     * 用于生成模拟异常数据(即垃圾数据)的方法<BR>
     * 异常通信数据种类描述:<BR>
     * ERROR-0 = 基站通信线程同步异常产生的数据都为NULL信息的通话日志<BR>
     * ERROR-1 = 被叫人号码非常规号码(未知号码)的通话日志<BR>
     * ERROR-2 = 没有接通状态与通话时长信息的通话日志<BR>
     * ERROR-3 = 只有主叫人信息的通话日志<BR>
     *
     * @return String 一条通话日志的垃圾数据
     */
    protected String generateRubbishDatas(String callLog) {
        //生成随机垃圾数据种类
        int rubbishType = random.nextInt(4);

        String[] callLogFields = callLog.split(" ");
        switch (rubbishType) {
            case 0:
                callLog = callLogFields[0] + " NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL";
                break;
            case 1:
                callLog = callLogFields[0] + " " + callLogFields[1] + " " + callLogFields[2] + " "
                        + callLogFields[3] + " " + callLogFields[4] + " " + callLogFields[5] + " "
                        + "* * * " + this.generateRandomLengthNumber() + " * "
                        + callLogFields[11] + " 0000 LOSS_CALL";
                break;
            case 2:
                callLog = callLogFields[0] + " " + callLogFields[1] + " " + callLogFields[2] + " "
                        + callLogFields[3] + " " + callLogFields[4] + " " + callLogFields[5] + " "
                        + callLogFields[6] + " " + callLogFields[7] + " " + callLogFields[8] + " "
                        + callLogFields[9] + " " + callLogFields[10] + " " + callLogFields[11];
                break;
            case 3:
                callLog = callLogFields[0] + " " + callLogFields[1] + " " + callLogFields[2] + " "
                        + callLogFields[3] + " " + callLogFields[4] + " " + callLogFields[5] + " "
                        + "     " + callLogFields[11] + " 0000 LOSS_CALL";
        }
        return callLog;

    }

    /**
     * 用于生成一个随机长度(最多22位)的数字字符串,用于表示错误的呼叫号码
     *
     * @return
     */
    protected String generateRandomLengthNumber() {
        StringBuilder builder = new StringBuilder();
        int length = random.nextInt(22) + 1;
        //用于验证标准手机号码的正则表达式,号段规则如下(截止2021年春节)
        //    	13 0123456789
        //    	14 145678
        //    	15 012356789
        //    	16 567
        //    	17 0145678
        //    	18 0123456789
        //    	19 189
        String mobileRegExp = "1((3[0-9])|(4[14-8])|(5[0-35-9])|(6[5-7])|(7[014-8])|(8[0-9])|(9[189]))\\d{8}";
        do {
            for (int i = 0; i < length; i++) {
                builder.append(random.nextInt(10));
            }
            if (length != 11) break;//减少正则验证压力,长度不是11则非手机号码
        } while (builder.toString().matches(mobileRegExp));
        return builder.toString();
    }

    /**
     * 将数据写入到文件中
     * @param strLogFilePath 将生成数据写入到的文件位置
     * @param strScale 随机联系人的体量
     * @param strStartDate 字符串格式起始日期,格式为:yyyy-MM-dd
     * @param strEndDate 字符串格式起始日期,格式为:yyyy-MM-dd
     */
    public void writeLog(String strLogFilePath, String strScale, String strStartDate, String strEndDate) {
    	OutputStreamWriter osw = null;
        try {
        	//将输出文件名称设置为结合流水号的拼接名称
//        	int fileIndex = 0;
//        	String fileName = FileUtils.getFileNameNoExtension(strLogFilePath);
//        	String extName = FileUtils.getFileExtension(strLogFilePath);
//        	String dirPath = FileUtils.getDirName(strLogFilePath);
//        	String logFilePath = dirPath + fileName + "-" + ++fileIndex + "." + extName;
//        	osw = new OutputStreamWriter(new FileOutputStream(logFilePath), "UTF-8");

        	osw = new OutputStreamWriter(new FileOutputStream(strLogFilePath), "UTF-8");
            while (true) {
            	//每1500毫秒随机产生0-100条通话记录
                Thread.sleep(500);
                StringBuffer buffer = new StringBuffer();
                int count = random.nextInt(100);
                for(int i=0; i<count; i++) {
	                String log = this.product(strScale, strStartDate, strEndDate);
	                if(random.nextInt(10)==1) {
	                	log = this.generateRubbishDatas(log);
	                }

	                buffer.append(log+"\n");
                }
                //一定要手动flush才可以确保每条数据都写入到文件一次，但这样性能不算好
                System.out.println(buffer.toString());
                osw.write(buffer.toString());
                osw.flush();

//            	//如果文件超过了127MB,则结合流水号生成新文件并将数据写入新文件中
//            	File file = FileUtils.getFileByPath(logFilePath);
//            	if(FileUtils.isFileExists(file) && FileUtils.getFileSize(file)>=127*1024*1024) {
//            		logFilePath = dirPath + fileName + "-" + ++fileIndex + "." + extName;
//            		osw = new OutputStreamWriter(new FileOutputStream(logFilePath), "UTF-8");
//            	}
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e2) {
            e2.printStackTrace();
        } finally {
			if(osw!=null)
				try {
					osw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
    }



    /**
     * 仿真系统运行入口主方法
     *
     * @param args 数据存储路径[ 通话数据生成范围的起始日期 通话数据生成范围的截止日期]
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        if (args == null || args.length <= 0) {
            System.out.println("no arguments");
            return;
        }
        //String logPath = "/tmp/calllog.csv";
        String logPath = args[0];
        String scale = "any";
        String startDate = "2021-01-01";
        //默认终止时间点为当前时间的上一天
        long endTime = System.currentTimeMillis() - 24 * 60 * 60 * 1000;
        String endDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date(endTime));

        // 传递两个参数时，数据规模根据参数决定(any|all)，否则默认为any
        if (args.length >= 2)
            scale = args[1];
        // 传递三个参数时，随机通话时间数据的起始时间点使用传递的参数，终止时间点使用默认值
        if (args.length >= 3)
            startDate = args[2];
        //传递四个以上参数时，随机通话时间数据的起始和终止时间点都使用传递的参数
        if (args.length >= 4)
            endDate = args[3];

        CallLogsFullSimulationProducer productLog = new CallLogsFullSimulationProducer();
        productLog.init(scale);
        productLog.writeLog(logPath, scale, startDate, endDate);
    }
}

